/*
 * @(#)FileTreeNode.java 10/9/2005
 *
 * Copyright 2002 - 2005 JIDE Software Inc. All rights reserved.
 */
package com.element.plaf.basic;

import com.element.ui.others.FolderChooser;

import javax.swing.*;
import java.io.File;
import java.util.*;

class BasicFileSystemTreeNode extends LazyMutableTreeNode implements Comparable {
	private FolderChooser _folderChooser;
	private File _file;

	static HashMap _icons = new HashMap();

	static HashMap _nodes = new HashMap();

	protected BasicFileSystemTreeNode(File file) {
		this(file, null);
	}

	protected BasicFileSystemTreeNode(File file, FolderChooser folderChooser) {
		_file = file;
		_folderChooser = folderChooser;
	}

	@Override
	public boolean isLeaf() {
		if (!isLoaded()) {
			return false;
		} else {
			return super.isLeaf();
		}
	}

	public boolean hasChildren() {
		if (!_loaded) {
			if (_file.exists() && _file.isDirectory()) {
				File[] files = _folderChooser.getFileSystemView().getFiles(_file, _folderChooser.isFileHidingEnabled());
				for (File file : files) {
					if (file.isDirectory()) {
						return true;
					}
				}
				_loaded = true; // no children so it is loaded
			}
			return false;
		} else {
			return getChildCount() != 0;
		}
	}

	@Override
	protected void initChildren() {
		if (_folderChooser == null) {
			return;
		}
		if (_file.isDirectory()) {
			File[] files = new File[0];
			try {
				files = _folderChooser.getFileSystemView().getFiles(_file, _folderChooser.isFileHidingEnabled());
				ArrayList<File> folders = new ArrayList();
				for (File file : files) {
					if (file.isDirectory()) {
						folders.add(file);
					}
				}
				files = folders.toArray(new File[0]);
				Comparator<File> comparator = _folderChooser.getFileComparator();
				if (comparator != null) {
					Arrays.sort(files, comparator);
				} else {
					Arrays.sort(files);
				}
			} catch (Error e) {
				// catch error like java.lang.InternalError: Unable to bind C:\blah blah\::{20D04FE0-3AEA-1069-A2D8-08002B30309D}\::{3D6BE802-FC0D-4595-A304-E611F97089DC} to parent
			} catch (Exception ignored) {
			}
			for (File file : files) {
				BasicFileSystemTreeNode fileTreeNode = BasicFileSystemTreeNode.createFileSystemTreeNode(file, _folderChooser);
				add(fileTreeNode);
			}
		}
	}

	public File getFile() {
		return _file;
	}

	public String getName() {
		return getName(getFile());
	}

	public Icon getIcon() {
		Icon icon = (Icon) _icons.get(this);
		if (icon == null) {
			icon = getIcon(getFile());
			_icons.put(this, icon);
		}
		return icon;
	}

	public String getTypeDescription() {
		String desc = getTypeDescription(getFile());
		return desc == null ? "" : desc;
	}

	public Icon getIcon(File file) {
		return _folderChooser.getFileSystemView().getSystemIcon(file);
	}

	public String getTypeDescription(File file) {
		return _folderChooser.getFileSystemView().getSystemTypeDescription(file);
	}

	public String getName(File file) {
		return _folderChooser.getFileSystemView().getSystemDisplayName(file);
	}

	@Override
	public boolean equals(Object o) {
		if (this == o) return true;
		if (o == null || getClass() != o.getClass()) return false;

		final BasicFileSystemTreeNode that = (BasicFileSystemTreeNode) o;

		return Objects.equals(_file, that._file);

	}

	public int compareTo(Object o) {
		if (!(o instanceof BasicFileSystemTreeNode)) {
			return 0;
		}
		return getFile().compareTo(((BasicFileSystemTreeNode) o).getFile());
	}

	@Override
	public int hashCode() {
		return (_file != null ? _file.hashCode() : 0);
	}

	public boolean canEnqueue() {
		return !isLoaded()
				&& !_folderChooser.getFileSystemView().isFloppyDrive(getFile())
				&& !_folderChooser.getFileSystemView().isFileSystemRoot(getFile());
	}

	@Override
	public String toString() {
		return _file != null ? _file.toString() : "null";
	}

	/**
	 * Caches the tree nodes ever created for the performance.
	 *
	 * @param file
	 * @param folderChooser
	 * @return tree node. If it is created before, returns the previous created instance.
	 */
	public static BasicFileSystemTreeNode createFileSystemTreeNode(File file, FolderChooser folderChooser) {
		BasicFileSystemTreeNode node = (BasicFileSystemTreeNode) _nodes.get(file);
		if (node == null) {
			node = new BasicFileSystemTreeNode(file, folderChooser);
			_nodes.put(file, node);
		}
		return node;
	}

	/**
	 * Clears the cache of all the tree nodes.
	 */
	public static void clearCache() {
		_nodes.clear();
	}
}
